#!/usr/bin/env python3
# Foundations of Python Network Programming, Third Edition
# https://github.com/brandon-rhodes/fopnp/blob/m/py3/chapter03/tcp_deadlock.py
# TCP client and server that leave too much data waiting

import argparse, socket, sys

def server(host, port):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind((host, port))
    sock.listen(1)
    print('Listening at', sock.getsockname())
    while True:
        sc, sockname = sock.accept()
        print('Processing up to 1024 bytes at a time from', sockname)
        n = 0
        while True:##### 50Mbps (峰值) 这个是我们阿里云服务器  传输速度。  50Mb每秒 6.25M/s 的速度
            data = sc.recv(1024)###每次接收1024个字节然后处理完毕，马上发送会给客户端的，这样就算客户端也不会把服务器的马上的内存ram消耗完毕。同一个服务器连接多个客户端
            if not data:
                break
            output = data.decode('ascii').upper().encode('ascii')
            sc.sendall(output)  # send it back uppercase
            n += len(data)
            print('\r  %d bytes processed so far' % (n,), end=' ')
            sys.stdout.flush()
        print()
        sc.close()
        print('  Socket closed')

##https://www.cnblogs.com/woaiyy/p/3554182.html tcp滑动窗口讲解得非常好
def client(host, port, bytecount):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    bytecount = (bytecount + 15) // 16 * 16  # round up to a multiple of 16
    message = b'capitalize this!'  # 16-byte message to repeat over and over

    print('Sending', bytecount, 'bytes of data, in chunks of 16 bytes')
    sock.connect((host, port))

    sent = 0             ###tcp滑动窗口 cwnd 是通信的双方一起协议的,   滑动窗口的数据的状态 4个   滑动窗口的左边 是1发送已确认的状态(客户端有确认收到的)，处于窗口之中有（2已发送但未确认的, 3允许发送的即将发送），窗口的右边不允许发送，滑动窗口还没滑动到
    while sent < bytecount:#########假如byteCount 是1G 那么问题来，客户端一下子sendAll需要把所有的1G数据发送完毕才开始recv确认服务端的已经收到，那么前面几兆客户端全部输出到缓冲区，服务端接收了，但是服务端滑动窗口的里面的所有数据却变了已发送未确认的状态，因为客户端没有及时确认收到,导致服务端的发送缓冲区满了，然后客户端的自己本身的输出缓冲区满了，
        sock.sendall(message)
        sent += len(message)
        print('\r  %d bytes sent' % (sent,), end=' ')
        sys.stdout.flush()

    print()
    sock.shutdown(socket.SHUT_WR)

    print('Receiving all the data the server sends back')

    received = 0
    while True:
        data = sock.recv(42)
        if not received:
            print('  The first data received says', repr(data))
        if not data:
            break
        received += len(data)
        print('\r  %d bytes received' % (received,), end=' ')

    print()
    sock.close()

if __name__ == '__main__':
    roles = ('client', 'server')
    parser = argparse.ArgumentParser(description='Get deadlocked over TCP')
    parser.add_argument('role', choices=roles, help='which role to play')
    parser.add_argument('host', help='interface the server listens at;'
                        ' host the client sends to')
    parser.add_argument('bytecount', type=int, nargs='?', default=16,
                        help='number of bytes for client to send (default 16)')
    parser.add_argument('-p', metavar='PORT', type=int, default=1060,
                        help='TCP port (default 1060)')
    args = parser.parse_args()
    if args.role == 'client':
        client(args.host, args.p, args.bytecount)
    else:
        server(args.host, args.p)
